package net.stuffrepos.bricknetcenter.gui.inventories;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import net.stuffrepos.bricknetcenter.database.DataEvent;
import net.stuffrepos.bricknetcenter.database.DataListener;
import net.stuffrepos.bricknetcenter.database.DataManager;
import net.stuffrepos.bricknetcenter.database.schema.Inventory;
import net.stuffrepos.bricknetcenter.database.schema.Transfer;
import net.stuffrepos.bricknetcenter.database.schema.TransferObject;
import net.stuffrepos.bricknetcenter.util.LocaleHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *
 * @author Eduardo H. Bogoni <eduardobogoni@gmail.com>
 */
public class BrowserTreeModel extends DefaultTreeModel {

    private static final Log log = LogFactory.getLog(BrowserTreeModel.class);
    private Map<Object, DefaultMutableTreeNode> objectNodes = new HashMap<Object, DefaultMutableTreeNode>();

    public BrowserTreeModel() {
        super(new RootTreeNode());
        DataManager.getInstance().addDataListener(new DataListener() {

            @Override
            public void dataChanged(DataEvent event) {
                BrowserTreeModel.this.dataChanged(event);
            }
        });
        populate();
    }

    private RootTreeNode getRootTreeNode() {
        return (RootTreeNode) getRoot();
    }

    private void dataChanged(DataEvent e) {
        for (Object obj : e.getAddedObjects()) {
            if (obj instanceof Inventory || obj instanceof Transfer) {
                addObject(obj);
            }
        }

        for (Object obj : e.getDeletedObjects()) {
            if (obj instanceof Inventory || obj instanceof Transfer) {
                deleteObject(obj);
            }
        }
    }

    private void populate() {
        try {
            for (Inventory inventory : DataManager.getInstance().findAllInventories()) {
                addObject(inventory);
                for (Transfer transfer : inventory.getTransfers()) {
                    addObject(transfer);
                }
            }
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }

    }

    private void addObject(Object object) {
        DefaultMutableTreeNode parentNode = getParentNode(object);
        assert parentNode != null;
        DefaultMutableTreeNode node = getObjectNode(object);
        assert node != null;
        this.insertNodeInto(node, parentNode, parentNode.getChildCount());
    }

    private void deleteObject(Object object) {
        DefaultMutableTreeNode node = getObjectNode(object);
        if (node != null) {
            this.removeNodeFromParent(node);
            objectNodes.remove(object);
        }
    }

    private DefaultMutableTreeNode getParentNode(Object obj) {
        if (obj == null) {
            return getRootTreeNode();
        } else if (obj instanceof Inventory) {
            return getRootTreeNode();
        } else if (obj instanceof Transfer) {
            return getObjectNode(((Transfer) obj).getInventory());
        } else if (obj instanceof RootTreeNode) {
            return null;
        } else {
            throw new RuntimeException("Parent node not mapped for " + obj);
        }
    }

    private DefaultMutableTreeNode getObjectNode(Object object) {
        assert object != null;
        DefaultMutableTreeNode node = objectNodes.get(object);
        if (node == null) {
            if (object instanceof Inventory) {
                node = new InventoryTreeNode((Inventory) object);
            } else if (object instanceof Transfer) {
                node = new TransferTreeNode((Transfer) object);
            }

            objectNodes.put(object, node);
        }
        return node;
    }

    public class InventoryTreeNode extends DefaultMutableTreeNode {

        public InventoryTreeNode(Inventory inventory) {
            super(inventory);
        }

        public Inventory getInventory() {
            return (Inventory) getUserObject();
        }

        @Override
        public String toString() {
            return getInventory().getName();
        }
    }

    public static class RootTreeNode extends DefaultMutableTreeNode {

        public RootTreeNode() {
        }

        @Override
        public String toString() {
            return "Informations";
        }
    }

    public class TransferTreeNode extends DefaultMutableTreeNode {

        public TransferTreeNode(Transfer transfer) {
            super(transfer);
        }

        @Override
        public String toString() {
            Iterator<TransferObject> objectIterator = getTransfer().getObjects().iterator();

            if (objectIterator.hasNext()) {
                TransferObject firstObject = getTransfer().getObjects().iterator().next();

                if (firstObject.getComments() != null && !firstObject.getComments().isEmpty()) {
                    return firstObject.getComments();
                }
            }

            if (getTransfer().getComments() != null && !getTransfer().getComments().isEmpty()) {
                return getTransfer().getComments();
            }

            if (getTransfer().getDate() != null) {
                return LocaleHelper.getDateOnlyInputFormat().format(getTransfer().getDate());
            }
            return LocaleHelper.getDateOnlyInputFormat().format(getTransfer().getCreatedOn());
        }

        public Transfer getTransfer() {
            return (Transfer) getUserObject();
        }
    }
}
